// Constructors/Destructors (构造函数/析构函数) 示例
// 演示 Pascal 中构造函数和析构函数的各种用法
program p_28_constructors_destructors;

{$mode objfpc}{$H+}
// {$mode objfpc} 启用 Object Pascal 模式，支持面向对象编程
// {$H+} 启用长字符串支持（AnsiString）

// 引入单元文件
uses
  SysUtils;  // 系统工具单元，包含常用的系统函数

// 定义一个简单的日志记录器类
type
  TLogger = class
  private
    FLogFileName: String;
    FLogFile: Text;
    FIsOpen: Boolean;
  public
    // 默认构造函数
    constructor Create; overload;
    
    // 带参数的构造函数
    constructor Create(const ALogFileName: String); overload;
    
    // 析构函数
    destructor Destroy; override;
    
    // 方法
    procedure Log(const Message: String);
    procedure OpenLog;
    procedure CloseLog;
    property LogFileName: String read FLogFileName;
    property IsOpen: Boolean read FIsOpen;
  end;

// TLogger类的实现
constructor TLogger.Create;
begin
  // 调用父类构造函数
  inherited Create;
  
  // 初始化默认值
  FLogFileName := 'default.log';
  FIsOpen := False;
  
  WriteLn('  TLogger 默认构造函数被调用');
end;

constructor TLogger.Create(const ALogFileName: String);
begin
  // 调用父类构造函数
  inherited Create;
  
  // 初始化指定值
  FLogFileName := ALogFileName;
  FIsOpen := False;
  
  WriteLn('  TLogger 带参数构造函数被调用，日志文件名: ', FLogFileName);
end;

destructor TLogger.Destroy;
begin
  // 确保在销毁前关闭日志文件
  if FIsOpen then
  begin
    Close(FLogFile);
    FIsOpen := False;
    WriteLn('  日志文件已关闭');
  end;
  
  WriteLn('  TLogger 析构函数被调用');
  
  // 调用父类析构函数
  inherited Destroy;
end;

procedure TLogger.OpenLog;
begin
  if not FIsOpen then
  begin
    Assign(FLogFile, FLogFileName);
    if FileExists(FLogFileName) then
      Append(FLogFile)
    else
      Rewrite(FLogFile);
    FIsOpen := True;
    WriteLn('  日志文件 ''', FLogFileName, ''' 已打开');
  end;
end;

procedure TLogger.CloseLog;
begin
  if FIsOpen then
  begin
    Close(FLogFile);
    FIsOpen := False;
    WriteLn('  日志文件已关闭');
  end;
end;

procedure TLogger.Log(const Message: String);
begin
  if not FIsOpen then
    OpenLog;
    
  WriteLn(FLogFile, DateTimeToStr(Now) + ' - ' + Message);
  Flush(FLogFile);  // 确保立即写入磁盘
  WriteLn('  已记录日志: ', Message);
end;

// 定义一个带有复杂初始化的类
type
  TDatabaseConnection = class
  private
    FConnectionString: String;
    FIsConnected: Boolean;
    FConnectionID: Integer;
  public
    // 构造函数
    constructor Create(const AConnectionString: String);
    
    // 析构函数
    destructor Destroy; override;
    
    // 方法
    function Connect: Boolean;
    procedure Disconnect;
    procedure ExecuteQuery(const Query: String);
    property IsConnected: Boolean read FIsConnected;
    property ConnectionID: Integer read FConnectionID;
  end;

// TDatabaseConnection类的实现
constructor TDatabaseConnection.Create(const AConnectionString: String);
begin
  inherited Create;
  
  FConnectionString := AConnectionString;
  FIsConnected := False;
  FConnectionID := Random(10000);  // 模拟连接ID
  
  WriteLn('  TDatabaseConnection 构造函数被调用');
  WriteLn('    连接字符串: ', FConnectionString);
  WriteLn('    连接ID: ', FConnectionID);
end;

destructor TDatabaseConnection.Destroy;
begin
  // 确保在销毁前断开连接
  if FIsConnected then
  begin
    Disconnect;
    WriteLn('  数据库连接已断开');
  end;
  
  WriteLn('  TDatabaseConnection 析构函数被调用');
  inherited Destroy;
end;

function TDatabaseConnection.Connect: Boolean;
begin
  // 模拟数据库连接
  WriteLn('  正在连接到数据库...');
  FIsConnected := True;
  Result := True;
  WriteLn('  数据库连接成功');
end;

procedure TDatabaseConnection.Disconnect;
begin
  if FIsConnected then
  begin
    WriteLn('  正在断开数据库连接...');
    FIsConnected := False;
    WriteLn('  数据库连接已断开');
  end;
end;

procedure TDatabaseConnection.ExecuteQuery(const Query: String);
begin
  if FIsConnected then
    WriteLn('  执行查询: ', Query)
  else
    WriteLn('  错误：未连接到数据库');
end;

// 程序主入口
begin
  WriteLn('=== Pascal 构造函数/析构函数示例 ===');
  WriteLn;
  
  // 1. 使用默认构造函数
  WriteLn('1. 使用默认构造函数:');
  var logger1: TLogger := TLogger.Create;
  try
    WriteLn('  日志文件名: ', logger1.LogFileName);
    logger1.Log('程序启动');
    logger1.Log('执行操作1');
  finally
    logger1.Free;
  end;
  
  WriteLn;
  
  // 2. 使用带参数的构造函数
  WriteLn('2. 使用带参数的构造函数:');
  var logger2: TLogger := TLogger.Create('application.log');
  try
    WriteLn('  日志文件名: ', logger2.LogFileName);
    logger2.Log('程序启动');
    logger2.Log('执行操作2');
  finally
    logger2.Free;
  end;
  
  WriteLn;
  
  // 3. 数据库连接对象的构造和析构
  WriteLn('3. 数据库连接对象的构造和析构:');
  var db: TDatabaseConnection := TDatabaseConnection.Create('Server=localhost;Database=test;User=admin;');
  try
    WriteLn('  连接ID: ', db.ConnectionID);
    if db.Connect then
    begin
      db.ExecuteQuery('SELECT * FROM users');
      db.ExecuteQuery('INSERT INTO logs VALUES (''test'')');
    end;
  finally
    db.Free;
  end;
  
  WriteLn;
  
  // 4. 多个对象的构造和析构顺序
  WriteLn('4. 多个对象的构造和析构顺序:');
  WriteLn('  创建对象1');
  var obj1: TLogger := TLogger.Create('obj1.log');
  
  WriteLn('  创建对象2');
  var obj2: TLogger := TLogger.Create('obj2.log');
  
  WriteLn('  创建对象3');
  var obj3: TDatabaseConnection := TDatabaseConnection.Create('connection3');
  
  WriteLn('  开始释放对象');
  obj1.Free;
  obj2.Free;
  obj3.Free;
  
  WriteLn;
  
  // 5. 异常情况下的构造和析构
  WriteLn('5. 异常情况下的构造和析构:');
  try
    WriteLn('  创建对象');
    var logger3: TLogger := TLogger.Create('exception.log');
    try
      WriteLn('  使用对象');
      logger3.Log('测试日志');
      
      // 模拟异常
      raise Exception.Create('模拟异常');
    finally
      WriteLn('  释放对象');
      logger3.Free;
    end;
  except
    on E: Exception do
      WriteLn('  捕获异常: ', E.Message);
  end;
  
  WriteLn;
  WriteLn('演示了 Pascal 中构造函数和析构函数的各种用法');
  
  // 等待用户按键，防止程序窗口立即关闭
  ReadLn;
end.